local Shared = require"ecs/shared/shared"
local astar = require"library.astar"

local function create_2d_array(xsize,ysize,start_value)
    local arr = {}
    for x = 1,xsize do
        arr[x] = {}
        for y = 1,ysize do
            if type(start_value) == "function" then
                arr[x][y] = start_value()
            else
                arr[x][y] = start_value
            end
        end
    end
    return arr
end

local function create_navigate_node()
    return {
        x = 0;
        y = 0;
    }
end

local sandbox = class("Sandbox"){
    areas = {},
    loading_areas = {};
    loading_center = {x = 0,y = 0,up_x = math.huge,up_y = math.huge};
    loading_size = 5;
    stop_size = 8;

    navigate = nil;
    _neighbors = {
            { 0, -1 }, 
    { -1, 0 },       { 1, 0 },
            { 0, 1 },
    }, 
}

function sandbox:__init__()
    self.navigate = astar.new(self)
end

function sandbox.wposi_to_aposi(wx,wy)--w : world  a : area posi: psoition
    return math.floor(wx / SANDBOX_AREA_PSIZE),math.floor(wy / SANDBOX_AREA_PSIZE)
end

function sandbox.apos_to_wposi(ax,ay)
    return ax * SANDBOX_AREA_PSIZE,ay * SANDBOX_AREA_PSIZE
end

function sandbox.wpos_to_gposi(wx,wy)
    return math.floor(wx / SANDBOX_GRID_PSIZE),math.floor(wy / SANDBOX_GRID_PSIZE)
end

function sandbox:get_area_from_wposi(wx,wy)
    return self:get_area(sandbox.wposi_to_aposi(wx,wy))
end

function sandbox:get_area(ax,ay)
    if not self.areas[ax] then
        self.areas[ax] = {}
    end
    if not self.areas[ax][ay] then
        local awx,awy = sandbox.apos_to_wposi(ax,ay)
        local area = box_core:create_entity("SandboxAreaEntity",{
            x = ax;
            y = ay;
            wx = awx;
            wy = awy; 
        })

        area.z_index = area.wy
        for lx = 1,SANDBOX_AREA_SIZE do
            area.grids[lx] = {}
            for ly = 1,SANDBOX_AREA_SIZE do
                area.grids[lx][ly] = {
                    --所在区块
                    ax = ax;
                    ay = ay;
                    --局部位置
                    lx = lx;
                    ly = ly;
                    --世界位置
                    x = awx + lx;
                    y = awy + ly;
                    tile = 0;
                    collision = false;
                }
            end
        end

        self.areas[ax][ay] =  area
    end
    return self.areas[ax][ay]
end

function sandbox:get_area_from_gposi(gwx,gwy)
    return self:get_area(gwx * SANDBOX_GRID_PSIZE,gwy * SANDBOX_GRID_PSIZE)
end

function sandbox:get_area_from_wposi(wx,wy)
    return self:get_area(sandbox.wposi_to_aposi(wx,wy))
end

function sandbox:get_grid(gwx,gwy)
    local area = self:get_area_from_gposi(gwx,gwy)
    local glx,gly = gwx - (area.x * SANDBOX_AREA_SIZE),gwy - (area.y * SANDBOX_AREA_SIZE)
    return area[glx][gly]
end

function sandbox:get_neighbors(node)
    local nodes = {}
    for i,offset in ipairs(self._neighbors) do
        local grid = self:get_grid(node.x + offset[1],node.y + offset[2])
        if grid.collision == false then
            table.insert(nodes,grid)
        end
    end
    return nodes
end

function sandbox:get_cost(from_node, to_node)
    local dx, dy = from_node.x - to_node.x, from_node.y - to_node.y
    return math.sqrt(dx * dx + dy * dy)
end

function sandbox:estimate_cost(node, goal_node)
    return self:get_cost(node, goal_node)
end

function sandbox:find_path(start_x,start_y,end_x,end_y)
    return self.navigate:find(
        self:get_grid(start_x,start_y),
        self:get_grid(end_x,end_y)
    )
end

return class("Sandbox",Shared){
    _create = function()
        return sandbox()
    end
}()


